using System;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;

internal static class WinInet
{
    // For PInvoke: Initiates the enumeration of the cache groups in the Internet cache
    [DllImport(@"wininet",
        SetLastError = true,
        CharSet = CharSet.Auto,
        EntryPoint = "FindFirstUrlCacheGroup",
        CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr FindFirstUrlCacheGroup(
        int dwFlags,
        int dwFilter,
        IntPtr lpSearchCondition,
        int dwSearchCondition,
        ref long lpGroupId,
        IntPtr lpReserved);

    // For PInvoke: Retrieves the next cache group in a cache group enumeration
    [DllImport(@"wininet",
        SetLastError = true,
        CharSet = CharSet.Auto,
        EntryPoint = "FindNextUrlCacheGroup",
        CallingConvention = CallingConvention.StdCall)]
    public static extern bool FindNextUrlCacheGroup(
        IntPtr hFind,
        ref long lpGroupId,
        IntPtr lpReserved);

    // For PInvoke: Releases the specified GROUPID and any associated state in the cache index file
    [DllImport(@"wininet",
        SetLastError = true,
        CharSet = CharSet.Auto,
        EntryPoint = "DeleteUrlCacheGroup",
        CallingConvention = CallingConvention.StdCall)]
    public static extern bool DeleteUrlCacheGroup(
        long groupId,
        int dwFlags,
        IntPtr lpReserved);

    // For PInvoke: Begins the enumeration of the Internet cache
    [DllImport(@"wininet",
        SetLastError = true,
        CharSet = CharSet.Auto,
        EntryPoint = "FindFirstUrlCacheEntryA",
        CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr FindFirstUrlCacheEntry(
        [MarshalAs(UnmanagedType.LPWStr)] string lpszUrlSearchPattern,
        IntPtr lpFirstCacheEntryInfo,
        ref int lpdwFirstCacheEntryInfoBufferSize);

    // For PInvoke: Retrieves the next entry in the Internet cache
    [DllImport(@"wininet",
        SetLastError = true,
        CharSet = CharSet.Auto,
        EntryPoint = "FindNextUrlCacheEntryA",
        CallingConvention = CallingConvention.StdCall)]
    public static extern bool FindNextUrlCacheEntry(
        IntPtr hFind,
        IntPtr lpNextCacheEntryInfo,
        ref int lpdwNextCacheEntryInfoBufferSize);

    // For PInvoke: Removes the file that is associated with the source name from the cache, if the file exists
    [DllImport(@"wininet",
        SetLastError = true,
        CharSet = CharSet.Auto,
        EntryPoint = "DeleteUrlCacheEntryA",
        CallingConvention = CallingConvention.StdCall)]
    public static extern bool DeleteUrlCacheEntry(
        IntPtr lpszUrlName);

    [DllImport("wininet.dll",
        SetLastError = true,
CharSet = CharSet.Unicode,
        EntryPoint = "InternetGetCookieEx",
        CallingConvention = CallingConvention.StdCall)]
    public static extern bool InternetGetCookieEx(
        string url,
        string? cookieName,
        StringBuilder cookieData,
        ref int size,
        int dwFlags,
        IntPtr lpReserved);

    //Read HTTP Only
    const int InternetCookieHttponly = 0x2000;

    public static CookieContainer? GetUriCookieContainer(Uri uri)
    {
        // First, create a null cookie container
        CookieContainer? cookies = null;

        // Determine the size of the cookie
        var datasize = 8192 * 16;
        var cookieData = new StringBuilder(datasize);

        // Call InternetGetCookieEx from wininet.dll
        if (!InternetGetCookieEx(uri.ToString(), null, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero))
        {
            if (datasize < 0)
                return null;
            // Allocate stringbuilder large enough to hold the cookie
            cookieData = new StringBuilder(datasize);
            if (!InternetGetCookieEx(
                uri.ToString(),
                null, cookieData,
                ref datasize,
                InternetCookieHttponly,
                IntPtr.Zero))
                return null;
        }

        // If the cookie contains data, add it to the cookie container
        if (cookieData.Length > 0)
        {
            cookies = new CookieContainer();
            cookies.SetCookies(uri, cookieData.ToString().Replace(';', ','));
        }

        // Return the cookie container
        return cookies;
    }
}